/**
TrakEM2 plugin for ImageJ(C).
Copyright (C) 2005-2009 Albert Cardona and Rodney Douglas.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation (http://www.gnu.org/licenses/gpl.txt )
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
You may contact Albert Cardona at acardona at ini.phys.ethz.ch
Institute of Neuroinformatics, University of Zurich / ETH, Switzerland.
**/
package ini.trakem2.tree;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragGestureRecognizer;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
/** Adapted from <a href="http://forum.java.sun.com/thread.jspa?threadID=296255&start=0&tstart=0">freely available code by DeuDeu</a>. */
public abstract class AbstractTreeTransferHandler implements DragGestureListener, DragSourceListener, DropTargetListener {
private DNDTree tree;
private DragSource dragSource;
private DropTarget dropTarget;
private static DefaultMutableTreeNode draggedNode;
private DefaultMutableTreeNode draggedNodeParent;
private static BufferedImage image = null; //buff image
private Rectangle rect2D = new Rectangle();
private boolean drawImage;
private DragGestureRecognizer dgr;
protected AbstractTreeTransferHandler(DNDTree tree, int action, boolean drawIcon) {
this.tree = tree;
drawImage = drawIcon;
if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance())
{
dragSource = new DragSource();
dgr = dragSource.createDefaultDragGestureRecognizer(tree, action, this);
dropTarget = new DropTarget(tree, action, this);
}
else
{
dragSource = null;
dgr = null;
dropTarget = null;
}
}
protected void destroy() {
if (dgr != null)
{
dgr.removeDragGestureListener(this);
dgr = null;
}
tree = null; // friggin' memory leak
dragSource = null;
if (dropTarget != null)
{
dropTarget.removeDropTargetListener(this);
dropTarget = null;
}
draggedNode = null;
draggedNodeParent = null;
image = null;
rect2D = null;
}
/* Methods for DragSourceListener */
public void dragDropEnd(DragSourceDropEvent dsde) {
if (dsde.getDropSuccess() && dsde.getDropAction()==DnDConstants.ACTION_MOVE && draggedNodeParent != null) {
((DefaultTreeModel)tree.getModel()).nodeStructureChanged(draggedNodeParent);
tree.expandPath(new TreePath(draggedNodeParent.getPath()));
tree.expandPath(new TreePath(draggedNode.getPath()));
}
}
public final void dragEnter(DragSourceDragEvent dsde) {
int action = dsde.getDropAction();
if (action == DnDConstants.ACTION_COPY) {
dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyDrop);
}
else {
if (action == DnDConstants.ACTION_MOVE) {
dsde.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
else {
dsde.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
}
}
}
public final void dragOver(DragSourceDragEvent dsde) {
int action = dsde.getDropAction();
if (action == DnDConstants.ACTION_COPY) {
dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyDrop);
}
else {
if (action == DnDConstants.ACTION_MOVE) {
dsde.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
else {
dsde.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
}
}
}
public final void dropActionChanged(DragSourceDragEvent dsde) {
int action = dsde.getDropAction();
if (action == DnDConstants.ACTION_COPY) {
dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyDrop);
}
else {
if (action == DnDConstants.ACTION_MOVE) {
dsde.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
else {
dsde.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
}
}
}
public final void dragExit(DragSourceEvent dse) {
dse.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
}
/* Methods for DragGestureListener */
public final void dragGestureRecognized(DragGestureEvent dge) {
TreePath path = tree.getSelectionPath();
if (path != null) {
draggedNode = (DefaultMutableTreeNode)path.getLastPathComponent();
draggedNodeParent = (DefaultMutableTreeNode)draggedNode.getParent();
if (drawImage) {
Rectangle pathBounds = tree.getPathBounds(path); //getpathbounds of selectionpath
JComponent lbl = (JComponent)tree.getCellRenderer().getTreeCellRendererComponent(tree, draggedNode, false , tree.isExpanded(path),((DefaultTreeModel)tree.getModel()).isLeaf(path.getLastPathComponent()), 0,false);//returning the label
lbl.setBounds(pathBounds);//setting bounds to lbl
image = new BufferedImage(lbl.getWidth(), lbl.getHeight(), java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE);//buffered image reference passing the label's ht and width
Graphics2D graphics = image.createGraphics();//creating the graphics for buffered image
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); //Sets the Composite for the Graphics2D context
lbl.setOpaque(false);
lbl.paint(graphics); //painting the graphics to label
graphics.dispose();
}
dragSource.startDrag(dge, DragSource.DefaultMoveNoDrop , image, new Point(0,0), new TransferableNode(draggedNode), this);
}
}
/* Methods for DropTargetListener */
public final void dragEnter(DropTargetDragEvent dtde) {
Point pt = dtde.getLocation();
int action = dtde.getDropAction();
if (drawImage) {
paintImage(pt);
}
if (canPerformAction(tree, draggedNode, action, pt)) {
dtde.acceptDrag(action);
}
else {
dtde.rejectDrag();
}
}
public final void dragExit(DropTargetEvent dte) {
if (drawImage) {
clearImage();
}
}
public final void dragOver(DropTargetDragEvent dtde) {
Point pt = dtde.getLocation();
int action = dtde.getDropAction();
tree.autoscroll(pt);
if (drawImage) {
paintImage(pt);
}
if (canPerformAction(tree, draggedNode, action, pt)) {
dtde.acceptDrag(action);
}
else {
dtde.rejectDrag();
}
}
public final void dropActionChanged(DropTargetDragEvent dtde) {
Point pt = dtde.getLocation();
int action = dtde.getDropAction();
if (drawImage) {
paintImage(pt);
}
if (canPerformAction(tree, draggedNode, action, pt)) {
dtde.acceptDrag(action);
}
else {
dtde.rejectDrag();
}
}
public final void drop(DropTargetDropEvent dtde) {
try {
if (drawImage) {
clearImage();
}
int action = dtde.getDropAction();
Transferable transferable = dtde.getTransferable();
Point pt = dtde.getLocation();
if (transferable.isDataFlavorSupported(TransferableNode.NODE_FLAVOR) && canPerformAction(tree, draggedNode, action, pt)) {
TreePath pathTarget = tree.getPathForLocation(pt.x, pt.y);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) transferable.getTransferData(TransferableNode.NODE_FLAVOR);
DefaultMutableTreeNode newParentNode = (DefaultMutableTreeNode)pathTarget.getLastPathComponent();
if (executeDrop(tree, node, newParentNode, action)) {
dtde.acceptDrop(action);
dtde.dropComplete(true);
return;
}
}
dtde.rejectDrop();
dtde.dropComplete(false);
}
catch (Exception e) {
System.out.println(e);
dtde.rejectDrop();
dtde.dropComplete(false);
}
}
private final void paintImage(Point pt) {
if (null == rect2D || null == image) {
return;
}
tree.paintImmediately(rect2D.getBounds());
rect2D.setRect((int) pt.getX(),(int) pt.getY(),image.getWidth(),image.getHeight());
tree.getGraphics().drawImage(image,(int) pt.getX(),(int) pt.getY(),tree);
}
private final void clearImage() {
tree.paintImmediately(rect2D.getBounds());
}
public abstract boolean canPerformAction(DNDTree target, DefaultMutableTreeNode nodeDragged, int action, Point location);
public abstract boolean executeDrop(DNDTree target, DefaultMutableTreeNode nodeDragged, DefaultMutableTreeNode newParentNode, int action);
}